package com.hiep.connect.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.hiep.connect.client.event.AcceptFriendEvent;
import com.hiep.connect.client.event.AcceptFriendEventHandler;
import com.hiep.connect.client.event.AddContactEvent;
import com.hiep.connect.client.event.AddContactEventHandler;
import com.hiep.connect.client.event.AddFriendEvent;
import com.hiep.connect.client.event.AddFriendEventHandler;
import com.hiep.connect.client.event.ContactUpdatedEvent;
import com.hiep.connect.client.event.ContactUpdatedEventHandler;
import com.hiep.connect.client.event.EditContactCancelledEvent;
import com.hiep.connect.client.event.EditContactCancelledEventHandler;
import com.hiep.connect.client.event.EditContactEvent;
import com.hiep.connect.client.event.EditContactEventHandler;
import com.hiep.connect.client.event.PostOnFriendEvent;
import com.hiep.connect.client.event.PostOnFriendEventHandler;
import com.hiep.connect.client.event.UserLoginEvent;
import com.hiep.connect.client.event.UserLoginEventHandler;
import com.hiep.connect.client.event.UserLogoutEvent;
import com.hiep.connect.client.event.UserLogoutEventHandler;
import com.hiep.connect.client.event.UserRegisterEvent;
import com.hiep.connect.client.event.UserRegisterEventHandler;
import com.hiep.connect.client.event.UserSearchEvent;
import com.hiep.connect.client.event.UserSearchEventHandler;
import com.hiep.connect.client.event.UserUpdateEvent;
import com.hiep.connect.client.event.UserUpdatedEventHandler;
import com.hiep.connect.client.presenter.ContactsPresenter;
import com.hiep.connect.client.presenter.EditProfilePresenter;
import com.hiep.connect.client.presenter.HomeViewPresenter;
import com.hiep.connect.client.presenter.LoginViewPresenter;
import com.hiep.connect.client.presenter.Presenter;
import com.hiep.connect.client.presenter.UserSearchResultPresenter;
import com.hiep.connect.client.view.ContactsView;
import com.hiep.connect.client.view.EditProfileView;
import com.hiep.connect.client.view.HomeView;
import com.hiep.connect.client.view.LoginView;
import com.hiep.connect.client.view.UserSearchResultView;
import com.hiep.connect.shared.MyUser;
import com.hiep.connect.shared.Posting;
import com.hiep.connect.shared.PostingThread;

public class AppController implements Presenter, ValueChangeHandler<String> {
	private final HandlerManager eventBus;
	// private final LoginServiceAsync loginService;
	// private final MyUserServiceAsync userService;
	private final UserRpcServiceAsync userService;

	// private final RegisterServiceAsync registerService;
	private HasWidgets container;
	private HomeView view;
	private List<MyUser> searchResult;

	ContactsServiceAsync contactRpcService = GWT.create(ContactsService.class);

	// public AppController(LoginServiceAsync loginService,
	// RegisterServiceAsync registerService, HandlerManager eventBus) {
	// this.eventBus = eventBus;
	// this.loginService = loginService;
	// this.registerService = registerService;
	// bind();
	// }

	public AppController(UserRpcServiceAsync useService, HandlerManager eventBus) {
		this.userService = useService;
		this.eventBus = eventBus;
		bind();
	}

	private MyUser user;

	private void bind() {
		History.addValueChangeHandler(this);

		eventBus.addHandler(AcceptFriendEvent.TYPE,
				new AcceptFriendEventHandler() {

					@Override
					public void onAcceptFriend(AcceptFriendEvent event) {
						// TODO Auto-generated method stub
						userService.acceptFriends(user,
								user.getPendingFriends(),
								new AsyncCallback<Void>() {

									@Override
									public void onFailure(Throwable caught) {
										// TODO Auto-generated method stub

									}

									@Override
									public void onSuccess(Void result) {
										// TODO Auto-generated method stub

									}
								});
					}

				});

		eventBus.addHandler(PostOnFriendEvent.TYPE,
				new PostOnFriendEventHandler() {

					@Override
					public void onUserPost(final PostOnFriendEvent event) {
						// TODO Auto-generated method stub
						Posting p = new Posting(event.getMessage());
						p.setEmail(event.getSource().getEmail());
						p.setDate(new Date());
						List<Posting> pList = new ArrayList<Posting>();
						pList.add(p);
						PostingThread thread = new PostingThread(pList);
						thread.setUpdateDate(new Date());

						userService.postOnFriend(event.getSource(),
								event.getTarget(), thread,
								new AsyncCallback<Void>() {

									@Override
									public void onFailure(Throwable caught) {
										// TODO Auto-generated method stub

									}

									@Override
									public void onSuccess(Void result) {
										// TODO Auto-generated method stub
										doOnPostedonFriend();
									}
								});

					}

				});

		eventBus.addHandler(AddFriendEvent.TYPE, new AddFriendEventHandler() {

			@Override
			public void onAddFriend(AddFriendEvent event) {
				// TODO Auto-generated method stub
				List<MyUser> selectedFriends = event.getSelectedFriends();
				userService.addPendingFriend(user, selectedFriends,
						new AsyncCallback<Void>() {

							@Override
							public void onFailure(Throwable caught) {
								// TODO Auto-generated method stub

							}

							@Override
							public void onSuccess(Void result) {
								// TODO Auto-generated method stub
								view.getStatus()
										.setText(
												"Add friend request has been sent for approval");

							}
						});

			}

		});

		eventBus.addHandler(UserSearchEvent.TYPE, new UserSearchEventHandler() {

			@Override
			public void onUserSearch(UserSearchEvent event) {
				// TODO Auto-generated method stub
				String searchFor = event.getSearchFor();

				userService.searchFor(searchFor,
						new AsyncCallback<List<MyUser>>() {

							@Override
							public void onFailure(Throwable caught) {
								// TODO Auto-generated method stub

							}

							@Override
							public void onSuccess(List<MyUser> result) {
								// TODO Auto-generated method stub
								doOnSearchSuccess(result);
							}

						});
			}

		});

		eventBus.addHandler(UserUpdateEvent.TYPE,
				new UserUpdatedEventHandler() {

					@Override
					public void onUserUpdate(UserUpdateEvent event) {
						// TODO Auto-generated method stub
						user = event.getUser();
						userService.update(user, new AsyncCallback<Void>() {

							@Override
							public void onFailure(Throwable caught) {
								// TODO Auto-generated method stub
								Window.alert("onUserUpdate failed");
							}

							@Override
							public void onSuccess(Void result) {
								// TODO Auto-generated method stub
								doAfterUpdate();
							}

						});

					}
				});

		eventBus.addHandler(UserLogoutEvent.TYPE, new UserLogoutEventHandler() {

			@Override
			public void onUserLogout(UserLogoutEvent event) {
				// TODO Auto-generated method stub
				user = event.getUser();
				userService.logout(user, new AsyncCallback<Void>() {

					@Override
					public void onFailure(Throwable caught) {
						// TODO Auto-generated method stub
						Window.alert("onUserLogout failed");
					}

					@Override
					public void onSuccess(Void result) {
						// TODO Auto-generated method stub
						doUserLogout(user);
					}
				});

			}
		});

		eventBus.addHandler(UserRegisterEvent.TYPE,
				new UserRegisterEventHandler() {

					@Override
					public void onUserRegister(UserRegisterEvent event) {
						// TODO Auto-generated method stub
						user = event.getUser();
						doRegisterUser(user);
					}
				});

		eventBus.addHandler(UserLoginEvent.TYPE, new UserLoginEventHandler() {

			@Override
			public void onUserLogin(UserLoginEvent event) {
				// TODO Auto-generated method stub

				user = event.getUser();
				doAfterLogin(user);
			}
		});

		eventBus.addHandler(AddContactEvent.TYPE, new AddContactEventHandler() {
			public void onAddContact(AddContactEvent event) {
				doAddNewContact();
			}
		});

		eventBus.addHandler(EditContactEvent.TYPE,
				new EditContactEventHandler() {
					public void onEditContact(EditContactEvent event) {
						doEditContact(event.getId());
					}
				});

		eventBus.addHandler(EditContactCancelledEvent.TYPE,
				new EditContactCancelledEventHandler() {
					public void onEditContactCancelled(
							EditContactCancelledEvent event) {
						doEditContactCancelled();
					}
				});

		eventBus.addHandler(ContactUpdatedEvent.TYPE,
				new ContactUpdatedEventHandler() {
					public void onContactUpdated(ContactUpdatedEvent event) {
						doContactUpdated();
					}
				});
	}

	private void doOnPostedonFriend() {
		// TODO Auto-generated method stub
		view.getStatus().setText("Message has been posted on friend's wall");
		History.newItem("home");
	}

	/**
	 * Load user home page.
	 * 
	 * @param user
	 */

	private void doOnSearchSuccess(List<MyUser> result) {
		// TODO Auto-generated method stub
		this.searchResult = result;
		History.newItem("searchResult");

	}

	private void doAfterUpdate() {
		History.newItem("home");
	}

	private void doAfterLogin(MyUser user) {
		History.newItem("home");
	}

	private void doRegisterUser(MyUser myUser) {
		userService.register(myUser.getEmail(), myUser.getPassword(),
				new AsyncCallback<MyUser>() {

					@Override
					public void onFailure(Throwable caught) {
						// TODO Auto-generated method stub
						Window.alert("Register failed");
					}

					@Override
					public void onSuccess(MyUser result) {
						// TODO Auto-generated method stub
						user = result;
						History.newItem("home");
					}

				});

	}

	private void doUserLogout(MyUser user) {
		History.newItem("login");
	}

	private void doAddNewContact() {
		History.newItem("add");
	}

	private void doEditContact(String id) {
	}

	private void doEditContactCancelled() {
		History.newItem("list");
	}

	private void doContactUpdated() {
		History.newItem("list");
	}

	public void go(final HasWidgets container) {
		this.container = container;
		History.newItem("");

		// user = createDummyUser();
		if ("".equals(History.getToken())) {
			History.newItem("login");
		} else {
			History.fireCurrentHistoryState();
		}
	}

	// private MyUser createDummyUser() {
	// MyUser user = new MyUser();
	// user.setEmail("Hiep@gmail.com");
	// List<MyUser> friends = new ArrayList<MyUser>();
	//
	// List<Posting> postings = new ArrayList<Posting>();
	//
	// for (int i = 1; i <= 10; i++) {
	// // Add friends.
	// MyUser u = new MyUser();
	// u.setEmail("friend " + i);
	// friends.add(u);
	//
	// // Create a posting thread.
	// Posting p = new Posting("Posting content" + i);
	// postings.add(p);
	// }
	//
	// PostingThread thread = new PostingThread(postings);
	// List<PostingThread> postingThreads = new ArrayList<PostingThread>();
	// postingThreads.add(thread);
	//
	// user.setFriends(friends);
	// user.setPostingThreads(postingThreads);
	//
	// return user;
	// }

	public void onValueChange(ValueChangeEvent<String> event) {
		String token = event.getValue();

		if (token != null) {
			Presenter presenter = null;
			if (token.equals("login")) {
				presenter = new LoginViewPresenter(userService, eventBus,
						new LoginView());

			} else if (token.equals("home")) {
				MultiWordSuggestOracle oracle = getOracle();
				view = new HomeView(user, oracle);
				presenter = new HomeViewPresenter(user, eventBus, view);

			} else if (token.equals("list")) {
				presenter = new ContactsPresenter(contactRpcService, eventBus,
						new ContactsView());

			} else if (token.equals("editProfile")) {
				presenter = new EditProfilePresenter(user, eventBus,
						new EditProfileView(user));
				presenter.go(view.getContentScrollPanel());
				return;

			} else if (token.equals("searchResult")) {
				presenter = new UserSearchResultPresenter(user, eventBus,
						new UserSearchResultView(user, searchResult));
				presenter.go(view.getContentScrollPanel());
				return;
			}

			if (presenter != null) {
				// TODO check user session before loading
				presenter.go(container);
			}
		}
	}

	private MultiWordSuggestOracle getOracle() {
		final MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();

		for (int i = 1; i <= 10; i++) {
			oracle.add("friend " + i);
			oracle.add("Posting content" + i);
		}

		userService.getAll(new AsyncCallback<List<MyUser>>() {

			@Override
			public void onSuccess(List<MyUser> result) {
				// TODO Auto-generated method stub
				for (MyUser user : result) {
					oracle.add(user.getEmail());
				}

			}

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				Window.alert("onFailure");
			}
		});

		return oracle;
	}
}
